/**
 * The base plugin container interface that all plugin containers are REQUIRED to implement.  
 * Some of the functions are pre-implemented, but may be overridden by the implementing container if needed.
 */
jsx3.lang.Class.defineInterface(
        "ux.megatron.plugin.PluginContainerInterface",
        null,
        function(container, container_prototype) {

            /**
             * {jsx3.util.List} a list of the plugin component instances loaded for this container
             * @private
             * @jsxobf-clobber
             */
            container_prototype.pluginList = null;

            /**
             * Abstract method to be implemented by implementing classes.  This will be called on each child plugin component instance
             * immediately after it's constructor is called, but before it's <code>initPlugin()</code> function is called.  This
             * allows for custom initialization to be done on the plugin objects before they are used.
             *
             * @param obj {Object} the object instance of the child plugin
             */
            container_prototype.setupPlugin = jsx3.lang.Method.newAbstract("obj");

            /**
             * Abstract method to be implemented by implementing classes.  This is called after all of the child plugin components
             * have been loaded, instantiated, and initialized.  This is where you make your class do something with the loaded
             * child plugins once they are ready to use.
             */
            container_prototype.onAfterGetPlugins = jsx3.lang.Method.newAbstract();

            container_prototype.isValidPlugin = function(obj) {
                try {
                    return obj.instanceOf("ux.megatron.plugin.PluginInterface");
                }
                catch(ex) {
                    return false;
                }
            }

            container_prototype.destroyPlugin = function() {
                var iter = this.getPluginList().iterator();
                while(iter.hasNext()) {
                    var nextPlugin = iter.next();
                    try {
                        nextPlugin.destroyPlugin();
                    }
                    catch(ex) {
                        ux.megatron.Main.logException(ex);
                    }
                }
            }

            /**
             * Either requests the implementing plugin components for this plugin container, or notifies the container
             * that they are ready to be used if we have already loaded them.  Should be called by the container when
             * they are ready to retrieve their child plugins.
             *
             * @param preLoadList {jsx3.util.List} a list of <code>jsx3.lang.Class</code> objects to treat as plugin classes
             *                    to be loaded prior to loading plugin classes.  This allows the internal loading of your own
             *                    components into the plugin list, prior to the plugins.  This also allows you to mandate that
             *                    your internal components appear first.  The classes in this list should NOT be specified as
             *                    implementing classes of <code>interfaces</code> in ANY of the <code>component.xml</code>
             *                    descriptor files!
             */
            container_prototype.loadPlugins = function(preLoadList) {
                if(this.getPluginList().size() == 0) {
                    if(preLoadList) {
                        var iter = preLoadList.iterator();
                        while(iter.hasNext()) {
                            try {
                                var obj = iter.next().getInstance(this.getPluginInitArgs());
                                if(this.isValidPlugin(obj)) {
                                    if(obj) {
                                        try {
                                            obj.initPlugin();
                                        }
                                        catch(ex1) {
                                            ux.megatron.Main.logException(ex1);
                                        }
                                        this.setupPlugin(obj);
                                        var me = this;
                                        obj.callbackTarget = me;
                                        obj.beginEditCallback = me.containerBeginEdit;
                                        obj.endEditCallback = me.containerEndEdit;
                                        var loadstatus = 200  ;
                                        var isalowed = false ;
                                        try {
                                            //TODO: by Eric
                                            var uiResources = obj.getUIResources();
                                            while(uiResources.hasNext()) {
                                                var uiResource = uiResources.next()
                                                var parentExtensionPoints = uiResource.getParentExtensionPoints()
                                                var pExtensionPoint;
                                                loadstatus = ux.megatron.Main.preLoadUIResource(obj.getNamespace(), uiResource.getPath())
                                                if(loadstatus == 403) {
                                                    ux.megatron.util.Log.SYSTEM.info("User dose not have access right to parent extension points " + parentExtensionPoints + " in plugin component  " + obj)
                                                }
                                                else {
                                                    isalowed = true;
                                                    while(parentExtensionPoints.hasNext()) {
                                                        parentExtensionPoint = parentExtensionPoints.next()
                                                        this.getPluginList(parentExtensionPoint).add(obj, this.getPluginList(parentExtensionPoint).size())
                                                    }
                                                }
                                            }
                                        }
                                        catch(e) {
                                            isalowed = true
                                            ux.megatron.util.Log.SYSTEM.info(" Faild to preloaed UI resource. Plugin:  " + obj)
                                        }
                                        if(isalowed) {
                                            this.getPluginList().add(obj, this.getPluginList().size());
                                            ux.megatron.util.Log.SYSTEM.info(" Added plugin  " + obj + " to the plugin list.")
                                        }
                                        else {
                                            ux.megatron.util.Log.SYSTEM.info("User dose not have access right to Plugin   " + obj)
                                        }
                                    }
                                }
                                else {
                                    jsx3.error(obj.jsxclass + " is not a valid plugin. It must implement ux.megatron.plugin.PluginInterface. Known interfaces it implements are:");
                                    for(name in obj) {
                                        jsx3.error("     Field: " + name);
                                    }
                                    try {
                                        var arr = obj.jsxclass.getInterfaces();
                                        for(var i = 0; i < arr.length; i++) {
                                            jsx3.error("     " + arr[i].getName());
                                        }
                                    }
                                    catch(ex1) {
                                        ux.megatron.Main.logException(ex1);
                                    }
                                }
                            }
                            catch(ex) {
                                ux.megatron.Main.logException(ex);
                            }
                        }
                    }
                    this.onAfterGetPlugins();
                }
                else {
                    this.onAfterGetPlugins();
                }
            }

            container_prototype.getPreLoadList = function() {
                if(this.preLoadList) {
                    this.preLoadList = new jsx3.util.List(0);
                }
                return this.preLoadList;
            }

            container_prototype.addPreLoadComponent = function(nameSpace, componentPath, classname, extensionPoints) {

            }

            container_prototype.onAfterContainerUnloaded = function() {
                var iter = this.getPluginList().iterator();
                while(iter.hasNext()) {
                    var nextPlugin = iter.next();
                    try {
                        nextPlugin.unload();
                    }
                    catch(ex) {
                        ux.megatron.Main.logException(ex);
                    }
                }
                this.onAfterComponentUnloaded();
            }

            container_prototype.unload = function() {
                this.onAfterContainerUnloaded();
            }

            container_prototype.onAfterComponentUnloaded = function() {
                try {
                    if(this.isInEditMode() && this.endEditMode) {
                        this.endEditMode();
                    }
                    ux.megatron.Main.logException(new jsx3.Exception("WARNING!!!!   The plugin " + this.getClass().getName() + " does not override the onAfterComponentUnloaded function to perform cleanup after it's main UI component is unloaded."));
                }
                catch (ex) {
                    // occasionally, harmless errors occur here when the ui is gone
                }
            }

            container_prototype.isInEditMode = function() {
                if(this.isEditMode) {
                    return true;
                }
                return this.childIsInEditMode();
            }

            container_prototype.childIsInEditMode = function() {
                var isEdit = false;
                var iter = this.getPluginList().iterator();
                while(iter.hasNext()) {
                    try {
                        var plugin = iter.next();
                        isEdit = plugin.isInEditMode();
                        if(isEdit) {
                            break;
                        }
                    }
                    catch(ex) {
                        // do nothing...treat it as false
                    }
                }
                return isEdit;
            }

            /**
             * Gets the list of child plugin component instances for this plugin container.  This method should NOT be
             * overridden by implementing plugins.
             * If extensionPoint not null then returns only the list of child plugin component instances for this plugin container that
             * user has access right for it's UI resource.
             *
             * @param  extensionPoint {String}
             * @return {jsx3.util.List} the list of child plugin component instances
             */
            container_prototype.getPluginList = function(extensionPoint) {
                if(this.pluginList == null) {
                    this.pluginList = new  jsx3.util.List(0);
                }
                if(extensionPoint) {
                    if(this.filteredPluginListObj == null) {
                        this.filteredPluginListObj = new  Object();
                    }
                    if(this.filteredPluginListObj[extensionPoint] == null)
                        this.filteredPluginListObj[extensionPoint] = new  jsx3.util.List(0);
                    return this.filteredPluginListObj[extensionPoint]
                }
                else {
                    return this.pluginList;
                }
            }

            container_prototype.getPluginInitArgs = function() {
                return null;
            }

            container_prototype.containerBeginEdit = function(objPlugin) {
                this.beginEdit(objPlugin);
            }

            container_prototype.containerEndEdit = function(objPlugin) {
                this.endEdit(objPlugin);
            }

            container_prototype.beginEdit = function(objPlugin) {
            }

            container_prototype.endEdit = function(objPlugin) {
            }

            container_prototype._allowComponentUnload = function(target, fctnYes, fctnNo, args) {
                if(!this.isEditMode) {
                    fctnYes.call(target, args);
                }
                else {
                    var me = this;
                    ux.megatron.Dialog.confirm(this.getConfirmTitle(), this.getConfirmText(),
                            function(dialog) {
                                dialog.doClose();
                                me.doCancelEdits();
                                fctnYes.call(target, args);
                            },
                            function(dialog) {
                                dialog.doClose();
                                if(fctnNo) {
                                    fctnNo.call(target, args);
                                }
                            },
                            this.getConfirmYesButtonText(), this.getConfirmNoButtonText(), this.getDefaultConfirmButton());
                }
            }

            container_prototype.getConfirmTitle = function() {
                return ux.megatron.Main.getServer().getDynamicProperty("@addin@PluginContainer Default Confirm Discard Title");
            }

            container_prototype.getConfirmText = function() {
                return ux.megatron.Main.getServer().getDynamicProperty("@addin@PluginContainer Default Confirm Discard Text");
            }

            container_prototype.getConfirmYesButtonText = function() {
                return ux.megatron.Main.getServer().getDynamicProperty("@addin@Btn Yes");
            }

            container_prototype.getConfirmNoButtonText = function() {
                return ux.megatron.Main.getServer().getDynamicProperty("@addin@Btn No");
            }

            container_prototype.getDefaultConfirmButton = function() {
                return 2;
            }

            container_prototype.childAllowsUnload = function(obj) {
                if(obj.iter.hasNext()) {
                    var me = this;
                    try {
                        obj.iter.next().allowComponentUnload(me, me.childAllowsUnload, me.childDisallowsUnload, obj);
                    }
                    catch(ex) {
                        // if the component throws an exception, treat it as a "true" so as not to block the switch
                        // due to a badly written component
                        me.childAllowsUnload(obj);
                    }
                }
                else {
                    this._allowComponentUnload(obj.target, obj.fctnYes, obj.fctnNo, obj.args);
                }
            }

            container_prototype.childDisallowsUnload = function(obj) {
                if(obj.fctnNo) {
                    obj.fctnNo.call(obj.target, obj.args);
                }
            };

            container_prototype.allowComponentUnload = function(target, fctnYes, fctnNo, args) {
                var obj = new Object();
                obj.iter = this.getPluginList().iterator();
                obj.target = target;
                obj.fctnYes = fctnYes;
                obj.fctnNo = fctnNo;
                obj.args = args;
                var me = this;
                if(obj.iter.hasNext()) {
                    obj.iter.next().allowComponentUnload(me, me.childAllowsUnload, me.childDisallowsUnload, obj);
                }
                else {
                    this._allowComponentUnload(target, fctnYes, fctnNo, args);
                }
            };

            container_prototype.doCancelEdits = function() {
            }
        }
        );